package com.kreig133.spine.builder;

import com.kreig133.builder.ParametrsForBuild;
import com.kreig133.spine.abstractmodel.AbstractSpine;
import com.kreig133.spine.abstractmodel.AbstractVelebra;
import com.kreig133.spine.interfaces.Algorithm;
import com.kreig133.spine.interfaces.Basement;
import com.kreig133.spine.interfaces.Spine;
import com.kreig133.spine.interfaces.Velebra;
import com.kreig133.spine.simplemodel.SimpleSpine;
import com.kreig133.spine.simplemodel.SimpleState;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 *
 * @author C.C.-fag
 */
class ModelBuilder implements AbstractBuilder {

    private SimpleSpine spine;
    List<Velebra> list = new ArrayList<Velebra>();

    /**
	 * 
	 * @param spineClass
	 * @return 
	 */
	@Override
	@SuppressWarnings("CallToThreadDumpStack")
    public void createSpine(String spineClass) {
        spine = new SimpleSpine();
    }

    @Override
    public void createVelebra(ParametrsForBuild parametrs) {
        final String algorithmKey = "algorithm";
        final String clazz = "class";

        for (Map<String, String> map : parametrs.getParametrs()) {
            try {
                //Если есть у звена алгоритм, то создаем его.
                Algorithm algorithm = null;
                if (map.containsKey(algorithmKey)) {
                    Class algorithmClass = Class.forName(map.get(algorithmKey));
                    map.remove(algorithmKey);
                    algorithm = (Algorithm) algorithmClass.newInstance();
                }
                //Получаем класс самого звена
                Class velebraClass = Class.forName(map.get(clazz));
                map.remove(clazz);

                Constructor constructor = null;
                AbstractVelebra velebra;
                //Если звено - основание.
                List intefaces = new ArrayList();
                Collections.addAll(intefaces, velebraClass.getInterfaces());
                if (intefaces.contains(Basement.class)) {
                    constructor = velebraClass.getConstructor(AbstractSpine.class);
                    velebra = (AbstractVelebra) constructor.newInstance(spine);
                    ((com.kreig133.spine.simplemodel.Basement) velebra).setState(new SimpleState(0.0, 0.0));
                } else {
                    for (Constructor c : velebraClass.getConstructors()) {
                        if (c.getParameterTypes().length == 2) {
                            constructor = c;
                            break;
                        }
                    }
                    velebra = (AbstractVelebra) constructor.newInstance(algorithm, spine);
                }
                //Устанавливаем остальные параметры.
                Method[] methods = velebraClass.getMethods();

                for (String key : map.keySet()) {
                    for (Method m : methods) {
                        if (m.getName().toLowerCase().equals("set" + key)) {
                            m.invoke(velebra,
                                    m.getParameterTypes()[0].getConstructor(String.class).newInstance(map.get(key)));
                        }
                    }
                }

                //Добавляем готовый позвонок в лист.
                list.add(velebra);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Spine getBuildedSpine() {
        ((AbstractSpine) spine).setVelebrae(list);
        return spine;
    }
}
